using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Miao;
using UnityEngine.Pool;

namespace Miao
{
    /// <summary>
    /// 音频播放2.0版使用UnityPool管理音频数据。
    /// </summary>
    static public class SoundManager
    {


        static SoundManager()
        {
            musicAudioTransform = new GameObject("BGMPlay", typeof(AudioSource)).transform;
            musicPlay = musicAudioTransform.GetComponent<AudioSource>();
            var sound = new GameObject("Sound", typeof(AudioSource));
            sound.transform.parent = musicAudioTransform;
            soundPlay = sound.GetComponent<AudioSource>();
            soundPlay.volume = 1;
            AddActiveSound(soundPlay);
            //{ hideFlags = HideFlags.HideInHierarchy };
            GameObject.DontDestroyOnLoad(musicAudioTransform);
            InitVolume();

            SoundPool = new ObjectPool<AudioSource>(
              createFunc: () =>
              {
                  // 修正了括号匹配问题
                  var obj = new GameObject(nameof(AudioSource), typeof(AudioSource));
                  obj.transform.parent = musicAudioTransform;
                  AudioSource audioSource = obj.GetComponent<AudioSource>();
                  return audioSource;
              },
              actionOnGet: audioSource => audioSource.gameObject.SetActive(true),
              actionOnRelease: audioSource => audioSource.gameObject.SetActive(false),
              actionOnDestroy: audioSource => GameObject.Destroy(audioSource.gameObject));

        }

        public const string MusicResPath = "Audios/Music/";
        public const string SoundResPath = "Audios/Sound/";
        readonly public static ObjectPool<AudioSource> SoundPool;//音频池
        readonly static private List<AudioSource> playAudioSources = new List<AudioSource>();//除背景音外拥有Unity自带的AudioSource的音频
        readonly static private Transform musicAudioTransform;
        readonly static public AudioSource musicPlay;//父类播放池，同时兼职音乐播放功能。
        readonly static public AudioSource soundPlay;//播放oneShot的audio预制件。


        static public void InitVolume()
        {
            if (PlayerPrefs.HasKey("Muisc"))
            {
                musicPlay.volume = PlayerPrefs.GetFloat("Muisc");
            }
            else
            {
                musicPlay.volume = 0.5f;
            }
            if (PlayerPrefs.HasKey("Sound"))
            {
                soundVolume = PlayerPrefs.GetFloat("Sound");
            }
            else
            {
                soundVolume = 1f;
            }
        }

        private static void AddActiveSound(AudioSource audioSound)
        {
            audioSound.volume = SoundVolume;
            playAudioSources.Add(audioSound);
        }

        private static void RemoveActiveSound(AudioSource audioSound)
        {
            playAudioSources.Remove(audioSound);
        }
        static private float soundVolume;

        static public bool StopSound { get; set; }
        static public bool StopMusic { get; set; }

        static public float MusicVolume//主要声音管理，默认bgm只会存在一首
        {
            get
            {
                return musicPlay.volume;
            }
            set
            {
                PlayerPrefs.SetFloat("Muisc", value);
                musicPlay.volume = value;

            }
        }
        static public float SoundVolume//每当有声音临时调整时，forech将已创造的音效进行同步调整。
        {
            get
            {
                return soundVolume;
            }
            set
            {
                PlayerPrefs.SetFloat("Sound", value);
                soundVolume = value;
                playAudioSources.ForEach(delegate (AudioSource audioSouce)
                {
                    audioSouce.volume = soundVolume;
                });
            }
        }
        #region 常用功能
        ///已被取代
        //static IEnumerator IPlaySoundAudio(AudioClip audioClip)
        //{

        //    GameObject playObject = GameObjectPoolManager.CreateGameObjectType(musicAudioTransform, typeof(AudioSource));
        //    AudioSource audioSource = playObject.GetComponent<AudioSource>();
        //    audioSource.clip = audioClip;
        //    audioSource.Play();
        //    AddActiveSound(audioSource);
        //    yield return new WaitUntilTrue(() => !audioSource.isPlaying);
        //    //yield return new WaitRealtime(audioSource.clip.length);
        //    RemoveActiveSound(audioSource);
        //    GameObjectPoolManager.RemoveGameObjectType(playObject, typeof(AudioSource));
        //    yield break;
        //}

        /// <summary>
        /// 播放一个音乐
        /// </summary>
        /// <param name="namePath"></param>
        static public void PlayMusic(string namePath, bool loop)
        {
            if (StopMusic)
            {
                return;
            }
            musicPlay.clip = Resources.Load<AudioClip>($"{MusicResPath}{namePath}");
            musicPlay.time = 0;
            musicPlay.loop = loop;
            musicPlay.Play();
        }
        /// <summary>
        /// 播放音频，AudioSource会由系统播放后回收，不建议直接使用该低级封装
        /// </summary>
        /// <param name="audioClip"></param>
        /// <returns></returns>
        static public (AudioSource,ConditionCallHandle) PlayAudioClip(AudioClip audioClip)
        {
            var obj = SoundPool.Get();
            AudioSource audioSource = obj;
            audioSource.clip = audioClip;
            audioSource.Play();
            AddActiveSound(audioSource);
           ConditionCallHandle conditionCallHandle = MiaoRuntime.Updater.AddConditionCall(() =>
            {
                RemoveActiveSound(audioSource);
                SoundPool.Release(obj);
            }, () => !audioSource.isPlaying);
            conditionCallHandle.onStopped += (() =>
            {
                audioSource.Stop();
                RemoveActiveSound(audioSource);
                SoundPool.Release(obj);
            });

            return (audioSource,conditionCallHandle);
        }
        /// <summary>
        /// 播放一个需要满足条件的音频，AudioSource会由系统播放后回收，不建议直接使用该低级封装
        /// </summary>
        /// <param name="audioClip"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        static public AudioSource PlayConditionAudioClip(AudioClip audioClip,Func<bool> condition)
        {
            var obj = SoundPool.Get();
            AudioSource audioSource = obj;
            audioSource.clip = audioClip;
            audioSource.Play();
            audioSource.loop = true;
            AddActiveSound(audioSource);
            MiaoRuntime.Updater.AddConditionCall(() =>
            {
                audioSource.loop = false;
                RemoveActiveSound(audioSource);
                SoundPool.Release(obj);
            },condition);
            return audioSource;

        }

        /// <summary>
        /// 播放随机的短音效
        /// </summary>
        /// <param name="folderNamePath"></param>
        static public void PlayRandomAudioOneShot(string folderNamePath)
        {
            if (StopMusic)
            {
                return;
            }
            AudioClip[] audioGroup = Resources.LoadAll<AudioClip>($"{SoundResPath}{folderNamePath}");
            AudioClip audioClip = audioGroup[UnityEngine.Random.Range(0, audioGroup.Length)];
            soundPlay.PlayOneShot(audioClip);
        }

        /// <summary>
        /// 播放一个不能被终止的短音效
        /// </summary>
        /// <param name="namePath"></param>
        static public void PlayAudioOneShot(string namePath, float volume)
        {
            AudioClip audioClip = Resources.Load<AudioClip>($"{SoundResPath}{namePath}");
            soundPlay.PlayOneShot(audioClip, volume);
        }

        /// <summary>
        /// 播放一个音效
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        /// 
        static public void PlaySoundAudio(string namePath)
        {
            if (StopSound)
            {
                return;
            }
            AudioClip audioClip = Resources.Load<AudioClip>($"{SoundResPath}{namePath}");
            PlayAudioClip(audioClip);
        }
        /// <summary>
        /// 随机播放一个文件夹内的音效
        /// </summary>
        /// <param name="namePath=Relative path Audios/Sound/"></param>
        static public void PlayRandomAudio(string folderNamePath)
        {
            if (StopSound)
            {
                return;
            }
            AudioClip[] audio = Resources.LoadAll<AudioClip>($"{SoundResPath}{folderNamePath}");
            AudioClip audioClip = audio[UnityEngine.Random.Range(0, audio.Length)];
            PlayAudioClip(audioClip);
        }
        /// <summary>
        /// 播放一个音效，并配置音效组件
        /// </summary>
        /// <param name="namePath"></param>
        /// <returns></returns>
        static public void PlaySoundAudio(string namePath,Action<AudioSource> audioFunc)
        {
            if (StopSound)
            {
                return;
            }
            AudioClip audioClip = Resources.Load<AudioClip>($"{SoundResPath}{namePath}");
            audioFunc.Invoke(PlayAudioClip(audioClip).Item1);
        }
        /// <summary>
        /// 播放一个随机音效，并配置音效组件
        /// </summary>
        /// <param name="folderNamePath"></param>
        static public void PlayRandomAudio(string folderNamePath, Action<AudioSource> audioFunc)
        {
            if (StopSound)
            {
                return;
            }
            AudioClip[] audio = Resources.LoadAll<AudioClip>($"{SoundResPath}{folderNamePath}");
            AudioClip audioClip = audio[UnityEngine.Random.Range(0, audio.Length)];
            audioFunc.Invoke(PlayAudioClip(audioClip).Item1);
        }

        /// <summary>
        /// 循环播放音效直到满足条件
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="EndID = 需要传递给bool的参数"></param>
        /// <param name="boolAction"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        static public void PlaySoundLoopUntilFunc(string namePath, Func<bool> func)
        {
            if (StopSound)
            {
                return;
            }
            AudioClip Audio = Resources.Load<AudioClip>($"{SoundResPath}{namePath}");
            PlayConditionAudioClip(Audio, func);
        }
        #endregion
    }
}
